package com.seres.backend.admin;


import java.util.List;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;

public class ModulesParser {
	private static final int MAX_NR_OF_MODULES = 25;
	
	private static final int GAMESTRUCTURE_NAME_COL_NR = 2;
	private static final int GAMESTRUCTURE_NAME_ROW_NR = 2;
	
	private static final int CORE_MODULE_ID_COL_NR = 1;
	private static final int STAKEHOLDER_MODULE_ID_COL_NR = 8;
	private static final int RISK_MODULE_ID_COL_NR = 13;
	
	private static final int CORE_MODULE_TITLE_COL_NR = 2;
	private static final int STAKEHOLDER_MODULE_TITLE_COL_NR = 9;
	private static final int RISK_MODULE_TITLE_COL_NR = 14;
	
	private static final int CORE_FIRST_SCENARIO_ID_COL_NR = 3;
	private static final int STAKEHOLDER_FIRST_SCENARIO_ID_COL_NR = 10;
	
	private static final int CORE_STAKEHOLDER_ID_COL_NR = 4;
	private static final int STAKEHOLDER_STAKEHOLDER_ID_COL_NR = 11;
	
	private static final int EVAL_OF_RISK_IDX_IC_COL_NR = 5;
	private static final int CORE_EVAL_OF_ALL_STAKEHOLDERS_IC_COL_NR = 6;
	
	private static final int MESSAGE_ID_COL_NR = 15;
	
	private static final int RISK_EVAL_OF_ALL_STAKEHOLDERS_IC_COL_NR = 16;
	
	private static final int TITLE_COL_NR = 1;
	private static final int TITLE_ROW_NR = 4;
	private static final String TITLE = "core modules";
	
	private static final int DATA_START_ROW_NR = 6;
	
	private boolean dataEndReached = false;
	
	private XSSFSheet worksheet;
	private List<Integer> allowedStakeholderIds;
	private List<Integer> allowedMessageIds;
	
	public ModulesParser(XSSFSheet worksheet, List<Integer> allowedStakeholderIds, List<Integer> allowedMessageIds){
		setWorksheet(worksheet);
		setAllowedStakeholderIds(allowedStakeholderIds);
		setAllowedMessageIds(allowedMessageIds);
	}
	public ModulesParserResult parse(){
		ModulesParserResult modulesParserResult = new ModulesParserResult();
		String gameStructureName = getWorksheet().getRow(GAMESTRUCTURE_NAME_ROW_NR).getCell(GAMESTRUCTURE_NAME_COL_NR).getStringCellValue();
		modulesParserResult.setGameStructureName(gameStructureName);
		System.out.println("gameStructureName: " + gameStructureName);
		
		for(int i = 0; i < MAX_NR_OF_MODULES && !isDataEndReached(); i++){
			XSSFRow row = getWorksheet().getRow(DATA_START_ROW_NR + i);
			
			if(containsData(row,CORE_MODULE_ID_COL_NR)){
				modulesParserResult.addCoreModuleLine(parseCoreModule(row));
			}
			if(containsData(row,STAKEHOLDER_MODULE_ID_COL_NR)){
				modulesParserResult.addStakeholderModuleLine(parseStakeholderModule(row));
			}
			if(containsData(row,RISK_MODULE_ID_COL_NR)){
				modulesParserResult.addRiskModuleLine(parseRiskModule(row));
			}
			
			if(!containsData(row,CORE_MODULE_ID_COL_NR) && !containsData(row,STAKEHOLDER_MODULE_ID_COL_NR) && !containsData(row,RISK_MODULE_ID_COL_NR)){
				setDataEndReached(true);
			}
		}
		return modulesParserResult;
	}
	
	private RiskModuleLine parseRiskModule(XSSFRow row) {
		int moduleId = parseModuleId(row.getCell(RISK_MODULE_ID_COL_NR));
		String moduleTitle = parseModuleTitle(row.getCell(RISK_MODULE_TITLE_COL_NR));
		int messageId = parseMessageId(row.getCell(MESSAGE_ID_COL_NR));
		boolean evaluationOfAllStakeholdersIndicator = parseEvaluationOfAllStakeholdersIndicator(row.getCell(RISK_EVAL_OF_ALL_STAKEHOLDERS_IC_COL_NR));
		
		System.out.println("************* RISK MODULE");
		System.out.println("module id: " + moduleId);
		System.out.println("moduleTitle: " + moduleTitle);
		System.out.println("messageId: " + messageId);
		System.out.println("evaluationOfAllStakeholdersIndicator: " + evaluationOfAllStakeholdersIndicator);
		System.out.println("");
		
		return new RiskModuleLine(moduleId,moduleTitle,messageId,evaluationOfAllStakeholdersIndicator);
	}
	private StakeholderModuleLine parseStakeholderModule(XSSFRow row) {
		int moduleId = parseModuleId(row.getCell(STAKEHOLDER_MODULE_ID_COL_NR));
		String moduleTitle = parseModuleTitle(row.getCell(STAKEHOLDER_MODULE_TITLE_COL_NR));
		int firstScenarioId = parseFirstScenarioId(row.getCell(STAKEHOLDER_FIRST_SCENARIO_ID_COL_NR));
		int stakeholderId = parseStakeholderId(row.getCell(STAKEHOLDER_STAKEHOLDER_ID_COL_NR));	
		
		System.out.println("************* STAKEHOLDER MODULE");
		System.out.println("module id: " + moduleId);
		System.out.println("moduleTitle: " + moduleTitle);
		System.out.println("firstScenarioId: " + firstScenarioId);
		System.out.println("stakeholderId: " + stakeholderId);
		System.out.println("");
		
		return new StakeholderModuleLine(moduleId,moduleTitle,firstScenarioId,stakeholderId);
		
	}
	private CoreModuleLine parseCoreModule(XSSFRow row) {
		int moduleId = parseModuleId(row.getCell(CORE_MODULE_ID_COL_NR));
		String moduleTitle = parseModuleTitle(row.getCell(CORE_MODULE_TITLE_COL_NR));
		int firstScenarioId = parseFirstScenarioId(row.getCell(CORE_FIRST_SCENARIO_ID_COL_NR));
		
		int stakeholderId = 0;
		if(containsData(row.getCell(CORE_STAKEHOLDER_ID_COL_NR))){
			stakeholderId = parseStakeholderId(row.getCell(CORE_STAKEHOLDER_ID_COL_NR));						
		}

		boolean evaluationOfRiskIndexIndicator = parseEvaluationOfRiskIndexIndicator(row.getCell(EVAL_OF_RISK_IDX_IC_COL_NR));
		boolean evaluationOfAllStakeholdersIndicator = parseEvaluationOfAllStakeholdersIndicator(row.getCell(CORE_EVAL_OF_ALL_STAKEHOLDERS_IC_COL_NR));
		
		System.out.println("************* CORE MODULE");
		System.out.println("module id: " + moduleId);
		System.out.println("moduleTitle: " + moduleTitle);
		System.out.println("firstScenarioId: " + firstScenarioId);
		System.out.println("stakeholderId: " + stakeholderId);
		System.out.println("evaluationOfRiskIndexIndicator: " + evaluationOfRiskIndexIndicator);
		System.out.println("evaluationOfAllStakeholdersIndicator: " + evaluationOfAllStakeholdersIndicator);
		System.out.println("");
		
		return new CoreModuleLine(moduleId,moduleTitle,firstScenarioId,stakeholderId,evaluationOfRiskIndexIndicator, evaluationOfAllStakeholdersIndicator);
	}
	
	private int parseModuleId(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
			return (int) cell.getNumericCellValue();
		}
		else{
			throw new IllegalArgumentException("invalid module id cell");
		}
	}
	private int parseMessageId(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC && canHaveAsMessageId((int) cell.getNumericCellValue())){
			return (int) cell.getNumericCellValue();
		}
		else{
			throw new IllegalArgumentException("invalid message id cell");
		}
	}
	private boolean canHaveAsMessageId(int numericCellValue) {
		return getAllowedMessageIds().contains(numericCellValue);
	}
	private String parseModuleTitle(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_STRING){
			return cell.getStringCellValue();
		}
		else{
			throw new IllegalArgumentException("invalid module title cell");
		}
	}
	private int parseFirstScenarioId(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
			return (int) cell.getNumericCellValue();
		}
		else{
			throw new IllegalArgumentException("invalid first scenario id cell");
		}
	}

	private int parseStakeholderId(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC && canHaveAsStakeholderId((int) cell.getNumericCellValue())){
			return (int) cell.getNumericCellValue();
		}
		else{
			throw new IllegalArgumentException("invalid stakeholder id cell");
		}
	}
	private boolean containsData(XSSFCell cell){
		return cell.getCellType() != Cell.CELL_TYPE_BLANK;
	}
	private boolean parseEvaluationOfRiskIndexIndicator(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
			int indicator = (int) cell.getNumericCellValue();			
			if(indicator == 0){
				return false;
			}
			else if(indicator == 1){
				return true;
			}
			else{
				throw new IllegalArgumentException("indicator field does not contain a boolean value");
			}
		}
		else{
			throw new IllegalArgumentException("invalid evaluation of risk index indicator cell");
		}
	}
	private boolean parseEvaluationOfAllStakeholdersIndicator(XSSFCell cell){
		if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC){
			int indicator = (int) cell.getNumericCellValue();			
			if(indicator == 0){
				return false;
			}
			else if(indicator == 1){
				return true;
			}
			else{
				throw new IllegalArgumentException("indicator field does not contain a boolean value");
			}
		}
		else{
			throw new IllegalArgumentException("invalid evaluation of all stakeholders indicator cell");
		}
	}
	private boolean containsData(XSSFRow row, int offset){
		return row.getCell(offset).getCellType() != Cell.CELL_TYPE_BLANK;
	}
	private boolean isDataEndReached() {
		return dataEndReached;
	}
	private void setDataEndReached(boolean dataEndReached) {
		this.dataEndReached = dataEndReached;
	}
	private XSSFSheet getWorksheet() {
		return worksheet;
	}
	public boolean canHaveAsWorksheet(XSSFSheet worksheet){
		return worksheet.getRow(TITLE_ROW_NR).getCell(TITLE_COL_NR).getStringCellValue().toLowerCase().equals(TITLE);
	}
	private void setWorksheet(XSSFSheet worksheet) {
		if(canHaveAsWorksheet(worksheet)){
			this.worksheet = worksheet;
		}
		else{
			throw new IllegalArgumentException("invalid modules worksheet");
		}
		
	}
	private boolean canHaveAsStakeholderId(int numericCellValue) {
		return getAllowedStakeholderIds().contains(numericCellValue);
	}
	private void setAllowedStakeholderIds(List<Integer> allowedStakeholderIds) {
		this.allowedStakeholderIds = allowedStakeholderIds;
	}
	public List<Integer> getAllowedStakeholderIds() {
		return allowedStakeholderIds;
	}
	private void setAllowedMessageIds(List<Integer> allowedMessageIds) {
		this.allowedMessageIds = allowedMessageIds;
	}
	public List<Integer> getAllowedMessageIds() {
		return allowedMessageIds;
	}
}
